using System.Collections;
using UnityEngine;

public class OrbitCamera : MonoBehaviour
{
	private static OrbitCamera instance;

	private static GameObject parentObject;

	public new Camera camera;

	public new Light light;

	public GameObject target;

	public Vector3 targetPosition = Vector3.zero;

	public float angleHorizontal;

	public float angleVertical = 25f;

	public float distance = 50f;

	public float height = 1f;

	[HideInInspector]
	public Vector3 currentTargetPosition;

	[HideInInspector]
	public float currentAngleHorizontal;

	[HideInInspector]
	public float currentAngleVertical;

	[HideInInspector]
	public float currentDistance;

	[HideInInspector]
	public float currentHeight;

	public bool lerpUpdate = true;

	public float lerpFactorTargetPosition = 6f;

	public float lerpFactorAngleHorizontal = 6f;

	public float lerpFactorAngleVertical = 6f;

	public float lerpFactorDistance = 6f;

	public float lerpFactorHeight = 1f;

	[HideInInspector]
	public float acceleration = 1f;

	public static bool instantToTarget;

	public bool lateralView;

	public bool inAirView;

	public bool inAirViewAscending = true;

	public bool lockVertical;

	private bool freezed;

	private float timeStart;

	private float timeLimit;

	private CameraHorizontalFollowMode horizontalFollow;

	public Vector3 targetDirection = Vector3.forward;

	private string customBehaviour = string.Empty;

	private Vector3 customTargetDirection = Vector3.forward;

	private GameObject customTarget;

	private float customAngleHorizontal;

	private float customAngleVertical;

	private float customDistance;

	private float customHeight;

	private Vector3 customBallInitPos = Vector3.zero;

	private bool shaking;

	public static OrbitCamera GetInstance()
	{
		if (!instance)
		{
			parentObject = GameObject.Find("Z Camera");
			if (parentObject != null)
			{
				instance = parentObject.GetComponent<OrbitCamera>();
			}
			else
			{
				Debug.Log("WTF : no instance found for OrbitCamera");
			}
		}
		return instance;
	}

	private void Start()
	{
		targetPosition = target.transform.position;
		currentTargetPosition = targetPosition;
		currentAngleHorizontal = angleHorizontal;
		currentAngleVertical = angleVertical;
		currentDistance = distance;
		UpdateCamera();
		BallBehaviour.BallLiftOffEvent += OnBallLiftOff;
		BallBehaviour.BallLandedEvent += OnBallLanded;
		BallBehaviour.BallInAirPeakedEvent += OnBallInAirPeaked;
		BallBehaviour.BallResetEvent += OnBallReset;
		CameraViewTrigger.CameraViewTriggerEnterEvent += OnCameraViewTriggerEnter;
		CameraViewTrigger.CameraViewTriggerExitEvent += OnCameraViewTriggerExit;
		EventManager.GameFreezeEvent += OnGameFreeze;
		EventManager.GameUnfreezeEvent += OnGameUnfreeze;
	}

	private void OnDestroy()
	{
		BallBehaviour.BallLiftOffEvent -= OnBallLiftOff;
		BallBehaviour.BallLandedEvent -= OnBallLanded;
		BallBehaviour.BallInAirPeakedEvent -= OnBallInAirPeaked;
		BallBehaviour.BallResetEvent -= OnBallReset;
		CameraViewTrigger.CameraViewTriggerEnterEvent -= OnCameraViewTriggerEnter;
		CameraViewTrigger.CameraViewTriggerExitEvent -= OnCameraViewTriggerExit;
		EventManager.GameFreezeEvent -= OnGameFreeze;
		EventManager.GameUnfreezeEvent -= OnGameUnfreeze;
	}

	private IEnumerator RenderOnce()
	{
		yield return new WaitForEndOfFrame();
		Debug.Log("RenderOnce");
		camera.Render();
	}

	private void OnGameFreeze()
	{
		freezed = true;
		shaking = false;
	}

	private void OnGameUnfreeze()
	{
		freezed = false;
	}

	public void Enable(bool enable = true)
	{
		camera.enabled = enable;
	}

	private void OnBallLiftOff()
	{
		if (!inAirView && BallBehaviour.GetInstance().velocity.y > 1f)
		{
			SwitchToAirView();
		}
	}

	private void OnBallLanded()
	{
		if (inAirView)
		{
			EndAirView();
		}
	}

	private void OnBallInAirPeaked()
	{
		if (inAirView)
		{
			inAirViewAscending = false;
		}
	}

	private void OnBallReset()
	{
		horizontalFollow = CameraHorizontalFollowMode.normal;
	}

	private void OnCameraViewTriggerEnter(CameraHorizontalFollowMode viewType, GameObject trigger)
	{
		horizontalFollow = viewType;
		if (viewType == CameraHorizontalFollowMode.fix)
		{
			customTargetDirection = trigger.transform.forward;
			float num = Vector3.Angle(trigger.transform.forward, BallBehaviour.GetInstance().gameObject.transform.position - trigger.transform.position);
			if (num < 90f)
			{
				customTargetDirection *= -1f;
			}
		}
	}

	private void OnCameraViewTriggerExit(CameraHorizontalFollowMode viewType, GameObject trigger)
	{
		horizontalFollow = CameraHorizontalFollowMode.normal;
	}

	private void LateUpdate()
	{
		if (!camera.enabled || freezed || target == null)
		{
			return;
		}
		Vector3 vector = Vector3.zero;
		if (customBehaviour != string.Empty)
		{
			if ((bool)customTarget)
			{
				targetDirection = customTarget.transform.forward;
				targetPosition = customTarget.transform.position;
			}
		}
		else
		{
			vector = BallBehaviour.GetInstance().velocity;
			targetDirection = BallBehaviour.GetInstance().heading.normalized;
			if (horizontalFollow == CameraHorizontalFollowMode.fix)
			{
				targetDirection = customTargetDirection;
			}
			targetPosition = BallBehaviour.GetInstance().transform.position;
		}
		float magnitude = vector.magnitude;
		float value = 90f - Vector3.Angle(Vector3.up, targetDirection);
		targetDirection.y = 0f;
		value = Mathf.Clamp(value, -60f, 90f);
		if (lateralView)
		{
			angleHorizontal = Vector3.Angle(Vector3.forward, targetDirection);
			if (targetDirection.x < 0f)
			{
				angleHorizontal = 360f - angleHorizontal;
			}
			angleHorizontal += 80f;
			if (Time.realtimeSinceStartup - timeStart < timeLimit)
			{
				Time.timeScale = Mathf.Lerp(Time.timeScale, 0.1f, 0.2f);
			}
			else
			{
				Time.timeScale = Mathf.Lerp(Time.timeScale, 1f, 0.08f);
			}
		}
		else
		{
			float num = Vector3.Angle(Vector3.forward, targetDirection);
			if (targetDirection.x < 0f)
			{
				num = 360f - num;
			}
			angleHorizontal = num;
			angleVertical = ConfigParams.camAngleVertical + value * -1f;
			if (lockVertical)
			{
				angleVertical = ConfigParams.camAngleVertical;
			}
			distance = ConfigParams.camDistance + Mathf.Pow((magnitude + 4f) * 0.02f, 2f) * 25f - 0.16f;
			float num2 = 1f - Mathf.Clamp(Mathf.Abs(value) / 5f, 0f, 1f);
			Vector3 vector2 = vector;
			vector2.y = 0f;
			lerpFactorAngleHorizontal = vector2.sqrMagnitude * 0.5f;
			if (horizontalFollow == CameraHorizontalFollowMode.slow)
			{
				lerpFactorAngleHorizontal = Mathf.Clamp(lerpFactorAngleHorizontal, 0.2f, 5f);
			}
			else
			{
				lerpFactorAngleHorizontal = Mathf.Clamp(lerpFactorAngleHorizontal, 0f * num2, 5f);
			}
			lerpFactorAngleVertical = magnitude * 1f + 0.1f;
			lerpFactorAngleVertical = Mathf.Clamp(lerpFactorAngleVertical, 0f, 2f);
			lerpFactorDistance = 4f;
			if (BallBehaviour.GetInstance().initState && magnitude < 0.01f)
			{
				lerpFactorAngleHorizontal = 5f;
				lerpFactorAngleVertical = 5f;
			}
		}
		if (inAirView)
		{
			if (inAirViewAscending)
			{
				angleVertical = ConfigParams.camAngleVertical;
				distance = ConfigParams.camDistance * 1.5f + magnitude * 0.08f;
				float y = vector.y;
				y = Mathf.Clamp(y, -10f, 10f);
				y = Mathf.Abs(y);
				lerpFactorHeight = y / 10f;
				lerpFactorDistance = y / 10f * 6f;
			}
			else
			{
				angleVertical = ConfigParams.camAngleVertical + value * 0.75f * -1f;
				height = 0f;
				distance = ConfigParams.camDistance * 1.5f + magnitude * 0.08f;
				float y2 = vector.y;
				y2 = Mathf.Clamp(y2, -10f, 10f);
				y2 = Mathf.Abs(y2);
				lerpFactorHeight = y2 / 20f;
				lerpFactorDistance = y2 / 20f * 6f;
				lerpFactorAngleVertical = y2 * 0.7f;
				lerpFactorAngleVertical = Mathf.Clamp(lerpFactorAngleVertical, 0f, 2f);
			}
		}
		if (customBehaviour == "gateopen")
		{
			distance = customDistance;
			lerpFactorDistance = 6f;
		}
		if (customBehaviour == "ballreset")
		{
			targetPosition = customTarget.transform.position;
			angleHorizontal = customAngleHorizontal;
			angleVertical = customAngleVertical;
			distance = customDistance;
			lerpFactorTargetPosition = 100f;
			lerpFactorAngleHorizontal = 100f;
			lerpFactorAngleVertical = 100f;
			lerpFactorDistance = 100f;
		}
		if (lerpUpdate)
		{
			UpdateCurrentValuesLerped();
		}
		else
		{
			UpdateCurrentValues();
		}
		if (instantToTarget)
		{
			UpdateCurrentValues();
			instantToTarget = false;
		}
		UpdateCamera();
	}

	private void UpdateCurrentValues()
	{
		currentTargetPosition = targetPosition;
		currentAngleHorizontal = angleHorizontal;
		currentAngleVertical = angleVertical;
		currentDistance = distance;
		currentHeight = height;
	}

	public void ApplyTargetValues()
	{
		UpdateCurrentValues();
	}

	public void ApplyCustomValues()
	{
		if ((bool)customTarget)
		{
			currentTargetPosition = customTarget.transform.position;
		}
		else
		{
			currentTargetPosition = targetPosition;
		}
		currentAngleHorizontal = customAngleHorizontal;
		currentAngleVertical = customAngleVertical;
		currentDistance = customDistance;
		currentHeight = customHeight;
	}

	private void UpdateCurrentValuesLerped()
	{
		if (Mathf.Abs(currentAngleHorizontal - angleHorizontal) > 180f)
		{
			if (angleHorizontal > currentAngleHorizontal)
			{
				currentAngleHorizontal += 360f;
			}
			else
			{
				currentAngleHorizontal -= 360f;
			}
		}
		float deltaTime = Time.deltaTime;
		currentTargetPosition = Vector3.Lerp(currentTargetPosition, targetPosition, deltaTime * lerpFactorTargetPosition * acceleration);
		if (lerpFactorAngleHorizontal > 0f)
		{
			float num = Mathf.Lerp(currentAngleHorizontal, angleHorizontal, deltaTime * lerpFactorAngleHorizontal * acceleration);
			float f = num - currentAngleHorizontal;
			if (Mathf.Abs(f) > 5f)
			{
				f = Mathf.Sign(f) * 5f;
				currentAngleHorizontal += f;
			}
			else
			{
				currentAngleHorizontal = num;
			}
		}
		else
		{
			float num2 = deltaTime * 30f * Mathf.Sign(angleHorizontal - currentAngleHorizontal);
			if (Mathf.Abs(currentAngleHorizontal - angleHorizontal) < 30f)
			{
				num2 = deltaTime * 1f * (angleHorizontal - currentAngleHorizontal);
			}
			if (Mathf.Abs(currentAngleHorizontal - angleHorizontal) > Mathf.Abs(num2))
			{
				currentAngleHorizontal += num2;
			}
		}
		currentAngleVertical = Mathf.Lerp(currentAngleVertical, angleVertical, deltaTime * lerpFactorAngleVertical * acceleration);
		currentDistance = Mathf.Lerp(currentDistance, distance, deltaTime * lerpFactorDistance * acceleration);
		currentHeight = Mathf.Lerp(currentHeight, height, deltaTime * lerpFactorHeight * acceleration);
		if (customBehaviour != "fly")
		{
			currentTargetPosition = targetPosition;
		}
		acceleration += deltaTime;
		if (acceleration > 1f)
		{
			acceleration = 1f;
		}
	}

	private void UpdateCamera()
	{
		base.transform.position = Quaternion.Euler(currentAngleVertical, currentAngleHorizontal, 0f) * new Vector3(0f, 1f, 0f - currentDistance) + currentTargetPosition;
		base.transform.rotation = Quaternion.Euler(currentAngleVertical, currentAngleHorizontal, 0f);
		base.transform.position += Vector3.up * currentHeight;
		light.transform.rotation = Quaternion.Euler(15f, currentAngleHorizontal, 0f);
	}

	public void SetDefaultLerpFactors()
	{
		lerpFactorTargetPosition = 6f;
		lerpFactorAngleHorizontal = 6f;
		lerpFactorAngleVertical = 6f;
		lerpFactorDistance = 6f;
		lerpFactorHeight = 6f;
	}

	private void ResetCustomValues()
	{
		customBehaviour = string.Empty;
		customTargetDirection = Vector3.forward;
		customTarget = null;
		customAngleHorizontal = 0f;
		customAngleVertical = 0f;
		customDistance = 0f;
		customHeight = 0f;
		customBallInitPos = Vector3.zero;
	}

	public void CustomBehaviourEndAll(float useAcceleration = 1f)
	{
		ResetCustomValues();
		acceleration = useAcceleration;
	}

	public void CustomBehaviourWatchSpawnPoint()
	{
		inAirView = false;
		customBehaviour = "watchspawnpoint";
		customTarget = SpawnPoint.GetGameObject();
		Vector3 forward = customTarget.transform.forward;
		forward.y = 0f;
		customAngleHorizontal = Vector3.Angle(Vector3.forward, forward);
		if (customTarget.transform.forward.x < 0f)
		{
			customAngleHorizontal = 360f - customAngleHorizontal;
		}
		customAngleVertical = ConfigParams.camAngleVertical;
		customDistance = ConfigParams.camDistance + 2f;
		targetPosition = customTarget.transform.position;
		angleVertical = customAngleVertical;
		angleHorizontal = customAngleHorizontal;
		distance = customDistance;
		height = 0f;
		currentHeight = height;
		UpdateCurrentValues();
		UpdateCamera();
	}

	public void CustomBehaviourGateOpenStart(GameObject gate)
	{
		inAirView = false;
		customBehaviour = "gateopen";
		customAngleHorizontal = gate.transform.eulerAngles.y;
		customAngleVertical = ConfigParams.camAngleVertical;
		customDistance = 6f;
		acceleration = 0.3f;
		height = 0f;
		currentHeight = height;
		customBallInitPos = BallBehaviour.GetInstance().transform.position;
		Vector3 from = gate.transform.position - customBallInitPos;
		float num = Vector3.Angle(from, gate.transform.forward);
		if (num > 90f)
		{
			customAngleHorizontal += 180f;
		}
	}

	public void CustomBehaviourGateOpenEnd()
	{
		if (customBehaviour == "gateopen")
		{
			ResetCustomValues();
			acceleration = 0f;
		}
	}

	public void CustomBehaviourOnBallResetStartDelayed(float delay)
	{
		Invoke("CustomBehaviourOnBallResetStart", delay);
	}

	public void CustomBehaviourOnBallResetStart()
	{
		inAirView = false;
		customBehaviour = "ballreset";
		GameObject gameObject = (customTarget = SpawnPoint.GetGameObject());
		customAngleHorizontal = Vector3.Angle(Vector3.forward, gameObject.transform.forward);
		if (gameObject.transform.forward.x < 0f)
		{
			customAngleHorizontal = 360f - customAngleHorizontal;
		}
		customAngleVertical = ConfigParams.camAngleVertical;
		customDistance = ConfigParams.camDistance + 2f;
		targetPosition = gameObject.transform.position;
		angleVertical = customAngleVertical;
		angleHorizontal = customAngleHorizontal;
		distance = customDistance;
		height = 0f;
		currentHeight = height;
		UpdateCurrentValues();
	}

	public void CustomBehaviourOnBallResetEndDelayed(float delay)
	{
		Invoke("CustomBehaviourOnBallResetEnd", delay);
	}

	public void CustomBehaviourOnBallResetEnd()
	{
		if (customBehaviour == "ballreset")
		{
			ResetCustomValues();
			acceleration = 0f;
		}
	}

	public void SwitchToLateralView()
	{
		float magnitude = target.GetComponent<Rigidbody>().velocity.magnitude;
		float num = 18f;
		float num2 = Mathf.Clamp(magnitude, 0f, num) / num;
		angleVertical = ConfigParams.camAngleVertical;
		distance = ConfigParams.camDistance + 6f * num2;
		height = -3f * num2;
		lerpFactorAngleHorizontal = -1f;
		lerpFactorDistance = 18f;
		lerpFactorHeight = 6f;
		acceleration = 0f;
		timeStart = Time.realtimeSinceStartup;
		timeLimit = 3f * num2;
		lateralView = true;
	}

	public void EndLateralView()
	{
		lateralView = false;
		height = 0f;
	}

	public void SwitchToAirView()
	{
		if (!lateralView && !inAirView)
		{
			float y = target.GetComponent<Rigidbody>().velocity.y;
			float num = 12f;
			float num2 = Mathf.Clamp(y, 0f - num, num) / num;
			distance = ConfigParams.camDistance + ConfigParams.camDistance * (5f * num2) * (5f * num2);
			angleVertical = ConfigParams.camAngleVertical;
			height = -18f * num2;
			height = Mathf.Clamp(height, -5f, 0f);
			lerpFactorHeight = 1f;
			inAirView = true;
			inAirViewAscending = true;
		}
	}

	public void EndAirView()
	{
		inAirView = false;
		height = 0f;
		lerpFactorHeight = 1f;
	}

	public void SetForGameStart()
	{
		angleHorizontal = Vector3.Angle(Vector3.forward, targetDirection);
		if (targetDirection.x < 0f)
		{
			angleHorizontal = 360f - angleHorizontal;
		}
		angleVertical = ConfigParams.camAngleVertical;
		distance = 1.5f;
		acceleration = 0f;
		height = 0f;
		customBehaviour = string.Empty;
		UpdateCurrentValues();
	}

	private static float ClampAngle(float angle, float min, float max)
	{
		if (angle < -360f)
		{
			angle += 360f;
		}
		if (angle > 360f)
		{
			angle -= 360f;
		}
		return Mathf.Clamp(angle, min, max);
	}

	private float NormalizeAngle(float angle)
	{
		angle %= 360f;
		if (angle < 0f)
		{
			angle = (angle + 360f) % 360f;
		}
		return angle;
	}

	public void Shake(float shakeDuration = 0.15f, float shakeMagnitude = 0.15f)
	{
		if (!shaking)
		{
			shaking = true;
			StartCoroutine(ShakeCo(shakeDuration, shakeMagnitude));
		}
	}

	private IEnumerator ShakeCo(float shakeDuration, float shakeMagnitude)
	{
		float elapsed = 0f;
		Vector3 originalCamPos = Vector3.zero;
		while (elapsed < shakeDuration && !BallBehaviour.GetInstance().isAirborne && shaking)
		{
			elapsed += Time.deltaTime;
			float percentComplete = elapsed / shakeDuration;
			float damper = 1f - Mathf.Clamp(4f * percentComplete - 3f, 0f, 1f);
			float x = Random.value * 2f - 1f;
			float y = Random.value * 2f - 1f;
			x *= shakeMagnitude * damper;
			y *= shakeMagnitude * damper;
			camera.transform.localPosition = new Vector3(x, y, originalCamPos.z);
			yield return null;
		}
		shaking = false;
		camera.transform.localPosition = originalCamPos;
	}
}
